package host.springboot.framework.core.page;

import host.springboot.framework.core.page.query.PageQuery;
import host.springboot.framework.core.response.vo.PageDetailVO;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.io.Serializable;
import java.util.Collection;
import java.util.Objects;

/**
 * 分页参数抽象类, 定义了默认的分页参数
 *
 * <p>框架默认提供了实现类, 如不满足使用需要可以自行继承该类:
 * <ul>
 *     <li><b>{@link ListPage}</b> - 默认分页对象, 其分页数据为 {@link java.util.List}</li>
 *     <li><b>{@link SetPage}</b> - 默认分页对象, 其分页数据为 {@link java.util.Set}</li>
 * </ul>
 *
 * @author JiYinchuan
 * @see Pageable
 * @see ListPage
 * @see SetPage
 * @since 1.0.0
 */
@ToString
@EqualsAndHashCode
public abstract class AbstractPageDetail<E, C extends Collection<E>> implements Pageable<C>, Serializable {

    /**
     * 页码
     */
    private Long pageNo;

    /**
     * 每页数量
     */
    private Long pageSize;

    /**
     * 数据总条数
     */
    private Long totalCount;

    /**
     * 构造器
     *
     * @since 1.0.0
     */
    protected AbstractPageDetail() {
    }

    /**
     * 构造器
     *
     * @param pageNo   页码
     * @param pageSize 每页数量
     * @since 1.0.0
     */
    protected AbstractPageDetail(long pageNo, long pageSize) {
        this();
        setPageNo(pageNo);
        setPageSize(pageSize);
    }

    /**
     * 构造器
     *
     * @param pageNo     页码
     * @param pageSize   每页数量
     * @param totalCount 数据总条数
     * @since 1.0.0
     */
    protected AbstractPageDetail(long pageNo, long pageSize, Long totalCount) {
        this();
        setPageNo(pageNo);
        setPageSize(pageSize);
        setTotalCount(totalCount);
    }

    /**
     * 构造器
     *
     * @param pageQuery 分页查询对象
     * @since 1.0.0
     */
    protected AbstractPageDetail(PageQuery pageQuery) {
        this();
        setPageNo(pageQuery.getPageNo());
        setPageSize(pageQuery.getPageSize());
    }

    /**
     * 构造器
     *
     * @param pageQuery  分页查询对象
     * @param totalCount 数据总条数
     * @since 1.0.0
     */
    protected AbstractPageDetail(PageQuery pageQuery, Long totalCount) {
        this();
        setPageNo(pageQuery.getPageNo());
        setPageSize(pageQuery.getPageSize());
        setTotalCount(totalCount);
    }

    /**
     * 构造器
     *
     * @param pageDetailVO 分页详情VO
     * @since 1.0.0
     */
    protected AbstractPageDetail(PageDetailVO pageDetailVO) {
        this();
        setPageNo(pageDetailVO.getPageNo());
        setPageSize(pageDetailVO.getPageSize());
        setTotalCount(pageDetailVO.getTotalCount());
    }

    @Override
    public Long getTotalCount() {
        return totalCount;
    }

    @Override
    public long getPageSize() {
        return pageSize;
    }

    @Override
    public long getPageNo() {
        return pageNo;
    }

    @Override
    public long getTotalPage() {
        long totalPage = 1;
        if (Objects.nonNull(totalCount)) {
            totalPage = (totalCount / pageSize);
            if (totalPage == 0 || totalCount % pageSize != 0) {
                totalPage++;
            }
        }
        return totalPage;
    }

    @Override
    public boolean isFirstPage() {
        return pageNo <= 1;
    }

    @Override
    public boolean isLastPage() {
        return pageNo >= getTotalPage();
    }

    @Override
    public long getNextPage() {
        if (isLastPage()) {
            return pageNo;
        } else {
            return pageNo + 1;
        }
    }

    @Override
    public long getPrePage() {
        if (isFirstPage()) {
            return pageNo;
        } else {
            return pageNo - 1;
        }
    }

    /**
     * 设置数据总条数
     *
     * @param totalCount 数据总条数
     * @return 当前实例
     * @since 1.0.0
     */
    public AbstractPageDetail<E, C> setTotalCount(Long totalCount) {
        this.totalCount = totalCount;
        adjustPageNo();
        return this;
    }

    /**
     * 设置每页数量
     *
     * @param pageSize 每页数量
     * @return 当前实例
     * @since 1.0.0
     */
    public AbstractPageDetail<E, C> setPageSize(long pageSize) {
        if (pageSize < 1) {
            this.pageSize = DEFAULT_PAGE_SIZE;
        } else {
            this.pageSize = Math.min(pageSize, DEFAULT_MAX_PAGE_SIZE);
        }
        adjustPageNo();
        return this;
    }

    /**
     * 设置页码
     *
     * @param pageNo 分页页码
     * @return 当前实例
     * @since 1.0.0
     */
    public AbstractPageDetail<E, C> setPageNo(long pageNo) {
        this.pageNo = Math.max(pageNo, DEFAULT_PAGE_NO);
        adjustPageNo();
        return this;
    }

    /**
     * 调整页码，使不超过最大页数
     *
     * @since 1.0.0
     */
    private void adjustPageNo() {
        if (pageNo == 1) {
            return;
        }
        long totalPage = getTotalPage();
        if (pageNo > totalPage) {
            pageNo = totalPage;
        }
    }
}
